/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pfc.generacion;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Types;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ddlutils.Platform;
import org.apache.ddlutils.model.Column;
import org.apache.ddlutils.model.Database;
import org.apache.ddlutils.model.Table;
import pfc.comun.IDEpfc;
import pfc.comun.Proyecto;
import pfc.modelocg.CGModel;
import pfc.modeloer.ERAttrib;
import pfc.modeloer.EREntity;
import pfc.modeloer.ERModel;
import pfc.utils.Utils;

/**
 *
 * @author xandru
 */
public class GeneradorPKGenerator {

    Proyecto _proyecto;
    Database _dbmodel;
    ERModel _erModel;
    CGModel _cgModel;
    PropertiesConfiguration conf;
    final String contadoresTableName = "_contadores";
    File _srcPath;

    public GeneradorPKGenerator(Proyecto pro, Database db, ERModel er, CGModel cg) {
        this._proyecto = pro;
        this._dbmodel = db;
        this._erModel = er;
        this._cgModel = cg;
        String dsFile = this._proyecto.getPath() + File.separator + "db" + File.separator + this._proyecto.getNombre() + "-ds.properties";
        conf = null;

        try {
            conf = new PropertiesConfiguration(dsFile);
        } catch (ConfigurationException ex) {
            Logger.getLogger(GeneradorPKGenerator.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void generar(File srcPath) {
        this._srcPath = srcPath;
        boolean tablaContadores = false;


        File f = new File(srcPath.getAbsolutePath() + File.separator + "PKGenerators");
        IDEpfc.log("\n=================Generando PKGenerators====================");

        try {
            FileUtils.forceMkdir(f);
        } catch (IOException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }



        Database auxmodel = Utils.getDatabaseModel(conf);

        for (Table t : auxmodel.getTables()) {
            if (t.getName().equals(contadoresTableName)) {
                tablaContadores = true;
            }
        }

        if (!tablaContadores) {
            generarTablaContadores();
        }


        for (EREntity ent : this._erModel.getEntityList()) {
            if (ent.isGenerateIdentity()) {
                generarPKGeneratorFile(f, ent);
            }
        }
    }

    private void generarTablaContadores() {
        Table tab = new Table();
        tab.setName(contadoresTableName);
        Column col = new Column();
        col.setName("contador");
        col.setPrimaryKey(true);
        col.setRequired(true);
        col.setTypeCode(Types.VARCHAR);
        tab.addColumn(col);

        col = new Column();
        col.setName("valornumerico");
        col.setPrimaryKey(false);
        col.setRequired(false);
        col.setTypeCode(Types.INTEGER);
        tab.addColumn(col);

        col = new Column();
        col.setName("valorcadena");
        col.setPrimaryKey(false);
        col.setRequired(false);
        col.setTypeCode(Types.VARCHAR);
        tab.addColumn(col);

        this._dbmodel.addTable(tab);
        Platform pf = Utils.getDatabasePlatform(conf);



    }

    private void generarPKGeneratorFile(File f, EREntity ent) {
        String clase = StringUtils.capitalize(ent.getName() + "PKGen");
        String claseDTO = StringUtils.capitalize(ent.getName());
        IDEpfc.logTime("generando " + clase);

        boolean numerico=false;
        boolean texto=false;
        for (ERAttrib a: ent.getPrimaryKeyAttribs())
        {
            if(a.isGenerable())
            {
                System.out.println("Attributo generable " + ent.getName() + "." + a.toString());
                numerico = a.isOfNumericType();
                texto = a.isOfTextType();
            }
        }

        try {
            PrintWriter o = new PrintWriter(new FileOutputStream(f.getAbsolutePath() + File.separator + clase + ".java"));

            o.println("package " + _proyecto.nombre + ".pkgen;\n");
            o.println("import pfc.core.db.*;");
            o.println("import javax.sql.DataSource;");
            o.println("import java.sql.Connection;");
            o.println("import java.sql.PreparedStatement;");
            o.println("import java.sql.ResultSet;");

            o.println("public class " + clase + " {");
            o.println("private static final Object lock= new Object(){};");
            o.println("private static boolean iniciado=false;");
            o.println("private static String query=\"select max(valornumerico),max(valorcadena) from " +contadoresTableName+ " where contador = ? \";");
            o.println("private static String update=\"update " +contadoresTableName+ " set valornumerico=?,valorcadena=? where contador = ? \";");
            o.println("private static DataSource ds;");
            o.println("");


            o.println("public static PrimaryKey getNewPrimaryKey() {");
            o.println("checkInit(\"" + claseDTO + "\");");
            o.println("PrimaryKey pk = null;");
            o.println("try {");
            o.println("synchronized (lock) {");
            o.println(" Connection c = ds.getConnection();");
            o.println(" c.setAutoCommit(false);");
       o.println("System.out.println(query);");
            o.println(" PreparedStatement s = c.prepareStatement(query);");
            o.println(" s.setString(1,\"" + claseDTO + "\");");
            o.println(" ResultSet rs = s.executeQuery();");
            o.println(" rs.first();");
            o.println("int valnum = rs.getInt(1);");
            o.println("String valcad = rs.getString(2);");
            o.println("valnum += 1;");
            o.println("pk = new SinglePrimaryKey(new Integer(valnum).toString());");
            o.println("PreparedStatement s2 = c.prepareStatement(update);");
            o.println("s2.setInt(1,valnum);");
            o.println("s2.setString(2,new Integer(valnum).toString());");
            o.println("s2.setString(3,\"" + claseDTO + "\");");
            o.println("s2.execute();");
            o.println("c.commit();");
            o.println("rs.close();");
            o.println("s.close();");
            o.println("s2.close();");
            o.println("c.close();");
            o.println("}");
           

            o.println("} catch (java.sql.SQLException ex) {System.out.println(ex.getMessage());iniciado=false;}");



            o.println("return pk;");
            o.println("}");


            
            o.println("private static void checkInit(String clase){");
            o.println(" if (!iniciado){");
            o.println("init();");
            o.println("}");
            o.println("}");

            o.println("private static void init(){");
            o.println("String sqlquery=\"select count(*) from " + contadoresTableName + " where contador=?\";");
            o.println("String sqlinsert=\"insert into " + contadoresTableName + " (contador,valornumerico,valorcadena) values (?,?,?)\";");
            o.println("try {");
            o.println(" if (ds==null) ds = DataSourceFactory.getDataSourceFromJNDI(\"jdbc/" + this._proyecto.getNombre() + "\");");
            o.println(" Connection c = ds.getConnection();");
            o.println("PreparedStatement s = c.prepareStatement(sqlquery);");
            o.println("s.setString(1,\"" + claseDTO + "\");");
            o.println("ResultSet rs = s.executeQuery();");
            o.println("rs.first();");
            o.println("int count = rs.getInt(1);");
            o.println("if (count>0)");
        o.println(" System.out.println(\"OK\" + sqlquery + \" \" + rs.getString(1));");            
            o.println("else {");
            o.println("s = c.prepareStatement(sqlinsert);");
        o.println(" System.out.println(\"kk1\" + sqlinsert);");
            o.println("s.setString(1,\"" + claseDTO + "\");");
            o.println("s.setInt(2,1);");
            o.println("s.setString(3,\"" + new Integer(0).toString() + "\");");
            o.println("s.execute();");
            o.println("}");
            o.println("rs.close();");
            o.println("s.close();");
            o.println("c.close();");
            o.println("iniciado=true;");

            o.println("} catch (java.sql.SQLException ex) {System.out.println(ex.getMessage());iniciado=false;}");
            o.println("}");
            o.println("}");
            o.flush();
            o.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
}
